package com.bjut.vendormgrsys.service.impl;

import com.bjut.vendormgrsys.constant.Constant;
import com.bjut.vendormgrsys.constant.Constant.PositionStatus;
import com.bjut.vendormgrsys.constant.Constant.ResumeStatus;
import com.bjut.vendormgrsys.constant.Constant.RoleEnum;
import com.bjut.vendormgrsys.model.domain.PositionPO;
import com.bjut.vendormgrsys.model.domain.ResumePO;
import com.bjut.vendormgrsys.model.repository.PositionRepository;
import com.bjut.vendormgrsys.model.repository.ResumeRepository;
import com.bjut.vendormgrsys.service.ResumeService;
import com.bjut.vendormgrsys.support.bo.RoleBO;
import com.bjut.vendormgrsys.support.bo.UserBO;
import com.bjut.vendormgrsys.util.DateUtils;
import com.bjut.vendormgrsys.util.DateUtils.Deliver;
import com.bjut.vendormgrsys.util.JsonUtils;
import com.bjut.vendormgrsys.web.dto.other.Body3;
import com.bjut.vendormgrsys.web.dto.other.ResumeInfo;
import com.bjut.vendormgrsys.web.dto.other.ResumeSearch;
import com.bjut.vendormgrsys.web.dto.other.ResumeSearchQueryFilter;
import com.bjut.vendormgrsys.web.dto.Status;
import com.fasterxml.jackson.databind.JsonNode;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.Predicate;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;

@Service
public class ResumeServiceImpl implements ResumeService {

    @PersistenceContext
    private EntityManager entityManager;

    private final ResumeRepository repository;

    private final PositionRepository posRepository;

    @Autowired
    public ResumeServiceImpl(ResumeRepository repository, PositionRepository posRepository) {
        this.repository = repository;
        this.posRepository = posRepository;
    }

    @Override
    public void validResumeInfo(ResumeInfo body) {
        Assert.notNull(body.getInfo(), "[简历详情]不能为空");
        Assert.notNull(body.getMobile(), "[手机号]不能为空");
        Assert.notNull(body.getEmail(), "[电子邮箱]不能为空");
        Assert.notNull(body.getPositionName(), "[职位名称]不能为空");
        Assert.notNull(body.getPositionId(), "[职位ID]不能为空");
        Assert.notNull(body.getName(), "[姓名]不能为空");
    }

    @Override
    @Transactional
    public void saveResumePO(ResumeInfo body, String creator) {
        String positionId = body.getPositionId();
        if (!StringUtils.hasLength(positionId)) {
            throw new RuntimeException("职位ID不能为空！");
        }
        Optional<PositionPO> posById = posRepository.findById(positionId);
        if (!posById.isPresent()) {
            throw new RuntimeException("职位不存在：" + body.getPositionName());
        }
        PositionPO positionPO = posById.get();
        String status = positionPO.getStatus();
        if (PositionStatus.REVOKED.getKey().equals(status)) {
            throw new RuntimeException("该职位招聘已完结！");
        }
        String id = body.getId();
        ResumePO resumePO = null;
        boolean isPersist = true;
        if (StringUtils.hasLength(id)) {
            Optional<ResumePO> byId = repository.findById(id);
            if (byId.isPresent()) {
                resumePO = byId.get();
                if (ResumeStatus.PASS.getKey().equals(resumePO.getStatus())) {
                    throw new RuntimeException("该简历已通过对应职位的筛选，不允许修改！");
                } else if (ResumeStatus.REFUSE.getKey().equals(resumePO.getStatus())) {
                    throw new RuntimeException("该简历已被拒绝，不允许修改！");
                }
                isPersist = false;
            }
        }
        if (resumePO == null) {
            resumePO = new ResumePO();
            body.setId(null);
        }
        BeanUtils.copyProperties(body, resumePO, "status");
        Object info = body.getInfo();
        String s = JsonUtils.toString(info);
        resumePO.setInfo(s);
        resumePO.setCreator(creator);
        resumePO.setLastUpdated(DateUtils.now());
        resumePO.setStatus(ResumeStatus.RECOMMENDING.getKey());
        if (!isPersist) {
            entityManager.merge(resumePO);
        } else {
            entityManager.persist(resumePO);
        }
    }

    @Override
    public ResumeInfo findById(String id, UserBO user) {
        if (!StringUtils.hasLength(id)) {
            throw new RuntimeException("简历ID不能为空！");
        }
        ResumePO resumePO;
        List<RoleBO> role = user.getRole();
        String roleName = role.get(0).getName();
        if (RoleEnum.ROLE_HRBP.getKey().equals(roleName)) {
            // 只能查自己创建的职位所属的简历
            List<PositionPO> allByPrincipalEquals = posRepository.getAllByPrincipalEquals(user.getAccount());
            if (allByPrincipalEquals == null || allByPrincipalEquals.isEmpty()) {
                throw new RuntimeException("您还未创建职位，请先创建职位！");
            }
            List<String> collect = allByPrincipalEquals.stream().map(PositionPO::getId).collect(Collectors.toList());
            resumePO = repository.getByIdAndPositionIdIn(id, collect);
        } else if (RoleEnum.ROLE_VENDOR.getKey().equals(roleName)) {
            resumePO = repository.getByIdAndCreator(id, user.getId());
        } else if (
                RoleEnum.ROLE_ADMIN.getKey().equals(roleName)) {
            resumePO = repository.findById(id).orElse(null);
        } else {
            throw new RuntimeException("无权限查看简历详情");
        }
        if (resumePO == null) {
            throw new RuntimeException("简历信息不存在:" + id);
        }
        return getResumeInfo(resumePO);
    }

    private ResumeInfo getResumeInfo(ResumePO resumePO) {
        ResumeInfo resumeInfo = new ResumeInfo();
        BeanUtils.copyProperties(resumePO, resumeInfo);
        String info = resumePO.getInfo();
        Object o = JsonUtils.toBean(info, JsonNode.class);
        resumeInfo.setInfo(o);
        return resumeInfo;
    }

    @Override
    public long findAll(ResumeSearch body, List<ResumeInfo> items, UserBO user) {
        Pageable pageable = Constant.getPageable(body.getOffset(), body.getMax());
        List<RoleBO> role = user.getRole();
        String roleName = role.get(0).getName();
        String creator;
        List<String> posIdList;
        if (RoleEnum.ROLE_ADMIN.getKey().equals(roleName)) {
            // 可以查所有简历
            creator = null;
            posIdList = null;
        } else if (RoleEnum.ROLE_VENDOR.getKey().equals(roleName)) {
            // 只能查自己创建的简历
            creator = user.getId();
            posIdList = null;
        } else if (RoleEnum.ROLE_HRBP.getKey().equals(roleName)) {
            // 只能查自己创建的职位所属的简历
            creator = null;
            List<PositionPO> allByAccount = posRepository.getAllByPrincipalEquals(user.getAccount());
            posIdList = allByAccount.stream().map(PositionPO::getId).collect(Collectors.toList());
        } else {
            throw new RuntimeException("无权限查看简历列表");
        }
        Specification<ResumePO> specification = (Specification<ResumePO>) (root, query, builder) -> {
            List<Predicate> predicates = new ArrayList<>();
            ResumeSearchQueryFilter queryFilter = body.getQueryFilter();
            if (StringUtils.hasLength(creator)) {
                predicates.add(builder.equal(root.get("creator").as(String.class), creator));
            }
            if (posIdList != null) {
                CriteriaBuilder.In<String> in = builder.in(root.get("positionId").as(String.class));
                for (String posId : posIdList) {
                    in.value(posId);
                }
                predicates.add(in);
            }
            if (queryFilter != null) {
                String name = queryFilter.getName();
                if (StringUtils.hasLength(name)) {
                    predicates.add(builder.like(root.get("name").as(String.class), "%" + name + "%"));
                }
                String email = queryFilter.getEmail();
                if (StringUtils.hasLength(email)) {
                    predicates.add(builder.like(root.get("email").as(String.class), "%" + email + "%"));
                }
                String mobile = queryFilter.getMobile();
                if (StringUtils.hasLength(mobile)) {
                    predicates.add(builder.like(root.get("mobile").as(String.class), "%" + mobile + "%"));
                }
                String positionName = queryFilter.getPositionName();
                if (StringUtils.hasLength(positionName)) {
                    predicates.add(builder.like(root.get("positionName").as(String.class), "%" + positionName + "%"));
                }
                String positionId = queryFilter.getPositionId();
                if (StringUtils.hasLength(positionId)) {
                    predicates.add(builder.equal(root.get("positionId").as(String.class), positionId));
                }
                String status = queryFilter.getStatus();
                if (StringUtils.hasLength(status)) {
                    predicates.add(builder.equal(root.get("status").as(String.class), status));
                }
                String deliverDate = queryFilter.getDeliverDate();
                if (StringUtils.hasLength(deliverDate)) {
                    long to = DateUtils.now();
                    long from;
                    if (Deliver.DAY_OF_THREE.getKey().equals(deliverDate)) {
                        from = DateUtils.day3();
                    } else if (Deliver.WEEK_OF_ONE.getKey().equals(deliverDate)) {
                        from = DateUtils.week1();
                    } else if (Deliver.MONTH_OF_ONE.getKey().equals(deliverDate)) {
                        from = DateUtils.month1();
                    } else if (Deliver.MONTH_OF_SIX.getKey().equals(deliverDate)) {
                        from = DateUtils.month6();
                    } else {
                        from = to;
                    }
                    predicates.add(builder.between(root.get("createDate").as(Long.class), from, to));
                }
            }
            return builder.and(predicates.toArray(new Predicate[0]));
        };
        Page<ResumePO> pageAll = repository.findAll(specification, pageable);
        for (ResumePO resumePO : pageAll.getContent()) {
            items.add(getResumeInfo(resumePO));
        }
        return pageAll.getTotalElements();
    }

    @Override
    public List<Status> findAllStatus(UserBO user) {
        List<RoleBO> role = user.getRole();
        String roleName = role.get(0).getName();
        List<ResumePO> all;
        if (RoleEnum.ROLE_ADMIN.getKey().equals(roleName)) {
            // 可以查所有简历状态
            all = repository.findAll();
        } else if (RoleEnum.ROLE_VENDOR.getKey().equals(roleName)) {
            // 只能查自己创建的简历状态
            all = repository.getAllByCreator(user.getId());
        } else if (RoleEnum.ROLE_HRBP.getKey().equals(roleName)) {
            // 只能查自己创建的职位所属的简历状态
            List<PositionPO> allByAccount = posRepository.getAllByPrincipalEquals(user.getAccount());
            List<String> posIdList = allByAccount.stream().map(PositionPO::getId).collect(Collectors.toList());
            all = repository.getAllByPositionIdIn(posIdList);
        } else {
            throw new RuntimeException("无权限查看简历列表");
        }
        Map<String, Long> collect = all.stream().collect(Collectors.groupingBy(ResumePO::getStatus, Collectors.counting()));
        Status[] array = new Status[4];
        int count = 0;
        for (String key : collect.keySet()) {
            int value = collect.get(key).intValue();
            Status status = new Status().key(key).name(Constant.getResumeStatusName(key)).value(value);
            if (ResumeStatus.RECOMMENDING.getKey().equals(key)) {
                array[1] = status;
            } else if (ResumeStatus.PASS.getKey().equals(key)) {
                array[2] = status;
            } else if (ResumeStatus.REFUSE.getKey().equals(key)) {
                array[3] = status;
            }
            count += value;
        }
        if (!collect.containsKey(ResumeStatus.RECOMMENDING.getKey())) {
            array[1] = new Status().key(ResumeStatus.RECOMMENDING.getKey()).name(ResumeStatus.RECOMMENDING.getName()).value(0);
        }
        if (!collect.containsKey(ResumeStatus.PASS.getKey())) {
            array[2] = new Status().key(ResumeStatus.PASS.getKey()).name(ResumeStatus.PASS.getName()).value(0);
        }
        if (!collect.containsKey(ResumeStatus.REFUSE.getKey())) {
            array[3] = new Status().key(ResumeStatus.REFUSE.getKey()).name(ResumeStatus.REFUSE.getName()).value(0);
        }
        array[0] = new Status().key(ResumeStatus.ALL.getKey()).name(ResumeStatus.ALL.getName()).value(count);
        return Arrays.asList(array);
    }

    @Override
    @Transactional
    public void updateResumePOByStatus(List<Body3> bodies) {
        for (Body3 body : bodies) {
            String id = body.getId();
            if (!StringUtils.hasLength(id)) {
                throw new RuntimeException("ID不能为空！");
            }
            String status = body.getStatus();
            if (!StringUtils.hasLength(status)) {
                throw new RuntimeException("状态不能为空！");
            }
            Constant.getResumeStatusName(status);
            if (!ResumeStatus.REFUSE.getKey().equals(status) &&
                    !ResumeStatus.PASS.getKey().equals(status)) {
                throw new RuntimeException("不允许设置的状态：" + status);
            }
            Optional<ResumePO> byId = repository.findById(id);
            if (!byId.isPresent()) {
                throw new RuntimeException("简历不存在！");
            }
            ResumePO resumePO = byId.get();
            if (ResumeStatus.REFUSE.getKey().equals(resumePO.getStatus())) {
                throw new RuntimeException("该简历已被拒绝，不允许变更状态");
            }
            if (ResumeStatus.PASS.getKey().equals(status)) {
                String positionId = resumePO.getPositionId();
                if (!StringUtils.hasLength(positionId)) {
                    throw new RuntimeException("职位不存在：" + resumePO.getPositionName());
                }
                Optional<PositionPO> posById = posRepository.findById(positionId);
                if (!posById.isPresent()) {
                    throw new RuntimeException("职位不存在：" + resumePO.getPositionName());
                }
                PositionPO positionPO = posById.get();
                String posStatus = positionPO.getStatus();
                if (!ResumeStatus.REFUSE.getKey().equals(status) &&
                        PositionStatus.REVOKED.getKey().equals(posStatus)) {
                    throw new RuntimeException("该职位招聘已完结！");
                }
            }
            resumePO.setStatus(status);
            resumePO.setLastUpdated(DateUtils.now());
            entityManager.merge(resumePO);
        }
        entityManager.flush();
    }
}
